#include "SPEmitterBeam.h"
#include "SPD3D11RenderEnvironment.h"
#include "SPCamera.h"

#ifndef PI
#define PI 3.141592653589793240
#endif

///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
namespace SP
{
	class SPEmitterBeamRenderer : public SPD3DObject
	{
		friend void SPRenderBeam( SPEmitterBeam* );
	protected:
		SPEmitterBeamRenderer();
		~SPEmitterBeamRenderer();

		void Render(SPEmitterBeam*);		
		HRESULT Create();

		struct CB
		{
			XMMATRIX mViewProj;	
			XMFLOAT4 vColor;
		};

		ID3D11InputLayout* m_pVertexLayout;
		ID3D11VertexShader* m_pVertexShader;
		ID3D11HullShader* m_pHullShader[64];
		ID3D11DomainShader* m_pDomainShader;
		ID3D11PixelShader* m_pPixelShader;
		ID3D11PixelShader* m_pPSTexture;
		ID3D11Buffer* m_pCB;
		ID3D11SamplerState* m_pSampleState;
	};

	void SPRenderBeam( SPEmitterBeam* pEB )
	{
		static SPEmitterBeamRenderer staticBRH;
		staticBRH.Render( pEB );
	}

	SPEmitterBeamRenderer::SPEmitterBeamRenderer()
	{
		Create();
	}

	SPEmitterBeamRenderer::~SPEmitterBeamRenderer()
	{
		SAFE_RELEASE( m_pPixelShader );
		SAFE_RELEASE( m_pVertexShader );
		SAFE_RELEASE( m_pVertexLayout );
		for ( int i = 0; i < 64; i++ )
			SAFE_RELEASE( m_pHullShader[i] );
		SAFE_RELEASE( m_pPSTexture );
		SAFE_RELEASE( m_pDomainShader );
		SAFE_RELEASE( m_pCB );
	}

	HRESULT SPEmitterBeamRenderer::Create()
	{
		HRESULT hr;

		// Create HullShaders
		for (int i = 0; i < 64; i++)
		{	
			ID3DBlob* pHSBlob = NULL;
			char strNum[5];
			sprintf_s( strNum, 5, "%d", i+1 );
			D3D_SHADER_MACRO defines[] = { { "TESS_AMOUNT", strNum }, { 0 } };
			V_RETURN( SPGetRenderEnvironment()->CompileShaderFromFile( L"hlsl\\Beam.hlsl", defines, "HSMain", "hs_5_0", &pHSBlob ) );
			V_RETURN( m_pDevice->CreateHullShader( pHSBlob->GetBufferPointer(), pHSBlob->GetBufferSize(), NULL, &m_pHullShader[i] ) );
			SAFE_RELEASE( pHSBlob );
		}

		// Create the shaders
		ID3DBlob* pVSBlob = NULL;
		ID3DBlob* pPSBlob = NULL;
		ID3DBlob* pDSBlob = NULL;
		ID3DBlob* pPSTexBlob = NULL;				

		V_RETURN( SPGetRenderEnvironment()->CompileShaderFromFile( L"hlsl\\Beam.hlsl", NULL, "VSMain", "vs_5_0", &pVSBlob ) );
		V_RETURN( SPGetRenderEnvironment()->CompileShaderFromFile( L"hlsl\\Beam.hlsl", NULL, "DSMain", "ds_5_0", &pDSBlob ) );
		V_RETURN( SPGetRenderEnvironment()->CompileShaderFromFile( L"hlsl\\Beam.hlsl", NULL, "PSMain", "ps_5_0", &pPSBlob ) );
		D3D_SHADER_MACRO defines[] = { { "TEXTURE", 0 }, { 0 } };
		V_RETURN( SPGetRenderEnvironment()->CompileShaderFromFile( L"hlsl\\Beam.hlsl", defines, "PSMain", "ps_5_0", &pPSTexBlob ) );

		V_RETURN( m_pDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pVertexShader ) );
		V_RETURN( m_pDevice->CreateDomainShader( pDSBlob->GetBufferPointer(), pDSBlob->GetBufferSize(), NULL, &m_pDomainShader ) );
		V_RETURN( m_pDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &m_pPixelShader ) );
		V_RETURN( m_pDevice->CreatePixelShader( pPSTexBlob->GetBufferPointer(), pPSTexBlob->GetBufferSize(), NULL, &m_pPSTexture ) );

		// Define the input layout
		D3D11_INPUT_ELEMENT_DESC layout[] =
		{
			{ "CP", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
			{ "SP", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12,  D3D11_INPUT_PER_VERTEX_DATA, 0 },		
		};
		UINT numElements = ARRAYSIZE( layout );
		// Create the input layout
		V_RETURN(m_pDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
			pVSBlob->GetBufferSize(), &m_pVertexLayout ) );

		SAFE_RELEASE( pVSBlob );
		SAFE_RELEASE( pPSBlob );
		SAFE_RELEASE( pDSBlob );
		SAFE_RELEASE( pPSTexBlob );

		// Create the constant buffers 
		D3D11_BUFFER_DESC Desc;
		Desc.Usage = D3D11_USAGE_DYNAMIC;
		Desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
		Desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
		Desc.MiscFlags = 0;
		Desc.ByteWidth = sizeof( CB );
		V_RETURN( m_pDevice->CreateBuffer( &Desc, NULL, &m_pCB ) );

		// CreateSampleState
		D3D11_SAMPLER_DESC SamplerDesc;
		ZeroMemory(  &SamplerDesc, sizeof( SamplerDesc ) );
		SamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
		SamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
		SamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
		SamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
		V_RETURN(  m_pDevice->CreateSamplerState( &SamplerDesc, &m_pSampleState ) );

		return S_OK;
	}

	void SPEmitterBeamRenderer::Render( SPEmitterBeam* pBeam )
	{
		SPCamera* pCamera = SPGetCamera();
		XMMATRIX mViewProj = pCamera->GetViewProjMtx();

		// Constant buffer
		D3D11_MAPPED_SUBRESOURCE MappedResource;
		m_pImmediateContext->Map( m_pCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource );
		CB* pCB = ( CB* )MappedResource.pData;
		pCB->mViewProj = XMMatrixTranspose( mViewProj );
		XMStoreFloat4( &pCB->vColor, pBeam->GetColourVector() );
		m_pImmediateContext->Unmap( m_pCB, 0 );

		m_pImmediateContext->VSSetConstantBuffers( 0, 1, &m_pCB );
		m_pImmediateContext->PSSetConstantBuffers( 0, 1, &m_pCB );

		// Set shaders
		m_pImmediateContext->VSSetShader( m_pVertexShader, NULL, 0 );
		m_pImmediateContext->DSSetShader( m_pDomainShader, NULL, 0 );
		m_pImmediateContext->GSSetShader( NULL, NULL, 0 );

		UINT iHS = pBeam->m_nTessellationAmount - 1;
		iHS = iHS > 0 ? iHS : 0;
		iHS = iHS < 64 ? iHS : 64;
		m_pImmediateContext->HSSetShader( m_pHullShader[iHS], NULL, 0 );

		if ( pBeam->m_pTexSRV )
		{
			m_pImmediateContext->PSSetShaderResources(  0, 1, &pBeam->m_pTexSRV );		
			m_pImmediateContext->PSSetShader( m_pPSTexture, NULL, 0 );
		}
		else
		{
			m_pImmediateContext->PSSetShader( m_pPixelShader, NULL, 0 );
		}

		// VertexBuffer & IndexBuffer
		m_pImmediateContext->IASetInputLayout(m_pVertexLayout);
		UINT Strides[1];
		UINT Offsets[1];
		ID3D11Buffer* pVB[1];
		pVB[0] = pBeam->m_pVertexBuffer;
		Strides[0] = sizeof( SPEmitterBeam::VERTEX );
		Offsets[0] = 0;
		m_pImmediateContext->IASetVertexBuffers( 0, 1, pVB, Strides, Offsets );

		m_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST );
		
		// SetSampleState
		m_pImmediateContext->PSSetSamplers(  0, 1, &m_pSampleState );
		// SetRasterizerState
		m_pImmediateContext->RSSetState( pBeam->GetRasterizerState() );
		// SetBlendState
		float vBlendFactor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
		m_pImmediateContext->OMSetBlendState( pBeam->GetBlendState(), vBlendFactor, 0xFFFFFFFF );
		// SetDepthStencilState
		m_pImmediateContext->OMSetDepthStencilState( pBeam->GetDepthStencilState(), 0 );



		// Draw 
		m_pImmediateContext->Draw( pBeam->m_nNumVertices - 8, 4 ) ;

		m_pImmediateContext->HSSetShader( NULL, NULL, 0 );
		m_pImmediateContext->DSSetShader( NULL, NULL, 0 );

		ID3D11Buffer* ppCBNULL[1] = { NULL };
		m_pImmediateContext->VSSetConstantBuffers( 0, 1, ppCBNULL );
		m_pImmediateContext->PSSetConstantBuffers( 0, 1, ppCBNULL );
	}
}

//--------------------------------------------------------------------------------------
// SPEmitterBeamAdvencer
//--------------------------------------------------------------------------------------
namespace SP
{
	class SPEmitterBeamAdvencer : public SPD3DObject
	{
		friend void SPAdvanceBeam( SPEmitterBeam*, FLOAT fElapsedTime );
	protected:
		SPEmitterBeamAdvencer();
		void Advance( SPEmitterBeam*, FLOAT fElapsedTime );	

		struct CB
		{			
			XMMATRIX mWorld;
			XMFLOAT3 vEyePos;
			FLOAT fWidth;

			FLOAT fSpeed;
			FLOAT fScale;
			FLOAT fElapsedTime;		
			FLOAT padding;				
		};

		ID3D11ComputeShader* m_pCSFaceToCamera;
		ID3D11ComputeShader* m_pCSFree;
		ID3D11Buffer* m_pCB;
	};

	void SPAdvanceBeam( SPEmitterBeam* pEB, FLOAT fElapsedTime  )
	{
		static SPEmitterBeamAdvencer staticEBA;
		staticEBA.Advance( pEB, fElapsedTime );
	}

	SPEmitterBeamAdvencer::SPEmitterBeamAdvencer()
	{
		HRESULT hr;

		m_pCSFaceToCamera = NULL;
		m_pCSFree = NULL;
		m_pCB = NULL;

		//	Create the constant buffer
		D3D11_BUFFER_DESC Desc;
		Desc.Usage = D3D11_USAGE_DYNAMIC;
		Desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
		Desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
		Desc.MiscFlags = 0;
		Desc.ByteWidth = sizeof( CB );
		V( m_pDevice->CreateBuffer( &Desc, NULL, &m_pCB ) );

		// Create the compute shader
		ID3DBlob* pCSBlob1 = NULL;
		ID3DBlob* pCSBlob2 = NULL;
		D3D_SHADER_MACRO defFree[] = { NULL, NULL	};
		D3D_SHADER_MACRO defFaceToCamera[] = { "FACE_TO_CAMERA", " ",	NULL, NULL };
		
		V( SPGetRenderEnvironment()->CompileShaderFromFile( L"hlsl\\BeamAdvancer_CS.hlsl", defFree, "CSMain", "cs_5_0", &pCSBlob1 ));
		V( SPGetRenderEnvironment()->CompileShaderFromFile( L"hlsl\\BeamAdvancer_CS.hlsl", defFaceToCamera, "CSMain", "cs_5_0", &pCSBlob2 ));

		V( m_pDevice->CreateComputeShader( pCSBlob1->GetBufferPointer(), pCSBlob1->GetBufferSize(), NULL, &m_pCSFree ) );
		V( m_pDevice->CreateComputeShader( pCSBlob2->GetBufferPointer(), pCSBlob2->GetBufferSize(), NULL, &m_pCSFaceToCamera ) );
	
		SAFE_RELEASE( pCSBlob1 );
		SAFE_RELEASE( pCSBlob2 );
	}

	void SPEmitterBeamAdvencer::Advance( SPEmitterBeam* pBeam, FLOAT fElapsedTime  )
	{
		SPCamera* pCamera = SPGetCamera();
		XMMATRIX mWorld = pBeam->GetTransformMatrix();

		// Set Constant buffer
		D3D11_MAPPED_SUBRESOURCE MappedResource;
		m_pImmediateContext->Map( m_pCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource );
		CB* pCS = ( CB* )MappedResource.pData;
		pCS->mWorld = XMMatrixTranspose( mWorld );
		pCS->fWidth = pBeam->m_fWidthScale;
		pCS->vEyePos = pCamera->GetEyePt();
		pCS->fElapsedTime = fElapsedTime;
		pCS->fScale = pBeam->m_fNoiseScale;
		pCS->fSpeed = pBeam->m_fNoiseSpeed;
		m_pImmediateContext->Unmap( m_pCB, 0 );

		m_pImmediateContext->CSSetConstantBuffers( 0, 1, &m_pCB );

		// Set compute shader
		if ( pBeam->m_bFaceToCamera )
			m_pImmediateContext->CSSetShader( m_pCSFaceToCamera, NULL, 0 );
		else
			m_pImmediateContext->CSSetShader( m_pCSFree, NULL, 0 );

		ID3D11ShaderResourceView* aRViews[ 1 ] = { pBeam->m_pSRVControlPoint };
		m_pImmediateContext->CSSetShaderResources( 0, 1, aRViews );

		ID3D11UnorderedAccessView* aUAViews[ 3 ] = { pBeam->m_pUAVPerlinSeed, pBeam->m_pUAVVertex };
		m_pImmediateContext->CSSetUnorderedAccessViews( 0, 3, aUAViews, (UINT*)( &aUAViews ) );

		// run
		m_pImmediateContext->Dispatch( pBeam->m_nNumControlPoint, 1, 1 );

		// clear
		ID3D11UnorderedAccessView* ppUAViewNULL[2] = { NULL, NULL };
		m_pImmediateContext->CSSetUnorderedAccessViews( 0, 2, ppUAViewNULL, NULL );

		ID3D11ShaderResourceView* ppSRVNULL[1] = { NULL};
		m_pImmediateContext->CSSetShaderResources( 0, 1, ppSRVNULL );

		ID3D11Buffer* ppCBNULL[1] = { NULL };
		m_pImmediateContext->CSSetConstantBuffers( 0, 1, ppCBNULL );

		m_pImmediateContext->CSSetShader( NULL, NULL, 0 );
	}
}


//-------------------------------------------------------------------------
// SPEmitterBeam
//-------------------------------------------------------------------------
namespace SP
{
	void SPEmitterBeam::SetZero()
	{
		m_nNumControlPoint = 0;
		m_nTessellationAmount = 0;
		m_nNumVertices = 0;

		m_bEnableNoise = TRUE;
		m_bFaceToCamera = FALSE;
		m_fWidthScale = 0.3f;

		m_pControlPoint = NULL;

		m_pControlPointBuffer = NULL;
		m_pPerlinSeedBuffer = NULL;
		m_pVertexBuffer = NULL;

		m_pSRVControlPoint = NULL;
		m_pUAVPerlinSeed = NULL;
		m_pUAVVertex = NULL;

		m_pTexSRV = NULL;
		m_pTex = NULL;

		m_fNoiseSpeed = 1.0f;
		m_fNoiseScale = 1.0f;

		ClearModule();
	}

	SPEmitterBeam::SPEmitterBeam()
	{
		SetZero();
		
		Create( 10 );
	}

	SPEmitterBeam::SPEmitterBeam( SPEmitterBeam* archetype )
		: SPEmitter( archetype )
	{
		SetZero();

		Create( archetype->m_nNumControlPoint );
	}

	void SPEmitterBeam::Release()
	{
		SAFE_DELETE( m_pControlPoint );

		SAFE_RELEASE( m_pControlPointBuffer );
		SAFE_RELEASE( m_pPerlinSeedBuffer );
		SAFE_RELEASE( m_pVertexBuffer );

		SAFE_RELEASE( m_pSRVControlPoint );
		SAFE_RELEASE( m_pUAVPerlinSeed );
		SAFE_RELEASE( m_pUAVVertex );
	}

	SPEmitterBeam::~SPEmitterBeam()
	{
		Release();
	}

	void SPEmitterBeam::Create( SPEmitterBeam* archetype )
	{

	}

	HRESULT SPEmitterBeam::Create( UINT nNumControlPoint )
	{
		HRESULT hr =S_OK;

		nNumControlPoint = ( nNumControlPoint%2 == 0 ) ? nNumControlPoint : nNumControlPoint - 1;
		nNumControlPoint = ( nNumControlPoint < 2 ) ? 2 : nNumControlPoint;
		nNumControlPoint = ( nNumControlPoint > 250 ) ? 250 : nNumControlPoint;
		nNumControlPoint += 4;
		if ( nNumControlPoint == m_nNumControlPoint )
			return S_OK;

		m_nNumControlPoint = nNumControlPoint;
		m_nNumVertices = m_nNumControlPoint * 2;

		// Release old resource
		Release();

		// Create new resource
		m_pControlPoint = new XMFLOAT3[ m_nNumControlPoint ];

		XMFLOAT3* pRandomize = new XMFLOAT3[m_nNumControlPoint];
		for (UINT i = 0 ; i < m_nNumControlPoint; i++)
		{
			pRandomize[i].x = SPRPresent() * 2000;
			pRandomize[i].y = SPRPresent() * 2000;
			pRandomize[i].z = SPRPresent() * 2000;
		}

		pRandomize[0] = pRandomize[m_nNumControlPoint - 4];
		pRandomize[1] = pRandomize[m_nNumControlPoint - 3];
		pRandomize[m_nNumControlPoint - 2] = pRandomize[2];
		pRandomize[m_nNumControlPoint - 1] = pRandomize[3];

		SPD3D11RenderEnvironment* pRE = SPGetRenderEnvironment();
		V_RETURN( pRE->CreateBuffer( sizeof( XMFLOAT3 ), m_nNumControlPoint, NULL, &m_pControlPointBuffer ) );
		V_RETURN( pRE->CreateBuffer( sizeof( XMFLOAT3 ), m_nNumControlPoint, pRandomize, &m_pPerlinSeedBuffer ) );
		V_RETURN( pRE->CreateBuffer( sizeof( VERTEX ), m_nNumVertices, NULL, &m_pVertexBuffer ) );

		SAFE_DELETE(pRandomize);

		V_RETURN( pRE->CreateBufferSRV(m_pControlPointBuffer, &m_pSRVControlPoint ) );
		V_RETURN( pRE->CreateBufferUAV(m_pPerlinSeedBuffer, &m_pUAVPerlinSeed ) );
		V_RETURN( pRE->CreateBufferUAV(m_pVertexBuffer, &m_pUAVVertex ) );


		Reshape();

		return hr;
	}

	void SPEmitterBeam::Reshape()
	{
		if ( !m_pModuleShape )
		{
			ReshapePoint();
		}
		else
		{
			switch ( m_pModuleShape->GetType() )
			{	
			case BS_POINT:
				ReshapePoint();
				break;
			case BS_LINE:		
				ReshapeLine();
				break;
			case BS_CURVE:
				ReshapeCurve();
				break;
			case BS_CIRCLE:
				ReshapeCircle();
				break;
			}
		}

		m_pImmediateContext->UpdateSubresource(m_pControlPointBuffer, NULL, NULL, m_pControlPoint, 0, 0);
	}

	void SPEmitterBeam::ReshapePoint()
	{
		ZeroMemory(m_pControlPoint, sizeof(XMFLOAT3) * m_nNumControlPoint);
	}

	void SPEmitterBeam::ReshapeLine()
	{
		float delta = 1.0f / ( m_nNumControlPoint - 5 );
		float t = 0.0f;

		XMFLOAT3 v0( 0.0f, 0.0f, 0.0f ), v1( 0.0f, 0.0f, 0.0f );
		if ( m_pModuleSource )
			m_pModuleSource->GetCP( v0, m_fEmitterLife );
		if ( m_pModuleTarget )
			m_pModuleTarget->GetCP( v1, m_fEmitterLife );
		XMVECTOR vSource = XMLoadFloat3( &v0 );
		XMVECTOR vTarget = XMLoadFloat3( &v1 );
		
		XMMATRIX mTransform = GetTransformMatrix();
		vSource = XMVector3Transform( vSource, mTransform );
		vTarget = XMVector3Transform( vTarget, mTransform );

		for (UINT i = 1; i < m_nNumControlPoint; i++)
		{
			XMVECTOR v = XMVectorLerp( vSource, vTarget, t );
			XMStoreFloat3( m_pControlPoint+i, v );
			t += delta;
		}
		m_pControlPoint[0] = m_pControlPoint[1];
		m_pControlPoint[m_nNumControlPoint - 1] = m_pControlPoint[m_nNumControlPoint - 2];
	
	}

	namespace 
	{
		void CalcBezier( XMFLOAT3& dst,  
			const float t, 
			const  XMFLOAT3& rsc0, 
			const  XMFLOAT3& rsc1, 
			const  XMFLOAT3& rsc2, 
			const  XMFLOAT3& rsc3)
		{
			float x, y, z, w;
			float invT = 1.0f - t;
			x = invT * invT * invT;
			y = 3.0f * t * invT * invT;
			z = 3.0f * t * t * invT;
			w = t * t * t ;

			dst.x = rsc0.x * x + rsc1.x * y + rsc2.x * z + rsc3.x * w;
			dst.y = rsc0.y * x + rsc1.y * y + rsc2.y * z + rsc3.y * w;
			dst.z = rsc0.z * x + rsc1.z * y + rsc2.z * z + rsc3.z * w;
		}
	}

	void SPEmitterBeam::ReshapeCurve()
	{
		float delta = 1.0f / ( m_nNumControlPoint - 5 );	
		XMFLOAT3 cp0,cp1,sp0,sp1;
		cp0 = cp1 = sp0 = sp1 = XMFLOAT3( 0.0f, 0.0f, 0.0f );
		if ( m_pModuleSource )
		{
			m_pModuleSource->GetCP( cp0, m_fEmitterLife );
			m_pModuleSource->GetSP( sp0, m_fEmitterLife );
		}
		if ( m_pModuleTarget )
		{	
			m_pModuleTarget->GetCP( cp1, m_fEmitterLife );
			m_pModuleTarget->GetSP( sp1, m_fEmitterLife );
		}

		for (UINT i = 1; i < m_nNumControlPoint; i++)
		{
			CalcBezier( m_pControlPoint[i], i * delta, sp0,cp0,cp1,sp1); 
		}
		m_pControlPoint[0] = m_pControlPoint[1];
		m_pControlPoint[m_nNumControlPoint - 1] = m_pControlPoint[m_nNumControlPoint - 2];
	}

	void SPEmitterBeam::ReshapeCircle()
	{	
		XMFLOAT3 center;
		FLOAT radius;
		m_pModuleShape->GetCircle( center, radius, m_fEmitterLife );

		float delta = 1.0f / ( m_nNumControlPoint - 4 );		
		float t = 0.0f;
		delta *= PI * 2;
		for (UINT i = 1 ; i < m_nNumControlPoint; i++)
		{
			m_pControlPoint[i].x = sin(t) * radius + center.x;
			m_pControlPoint[i].y = cos(t) * radius + center.y;
			m_pControlPoint[i].z = center.z;
			t += delta;
		}
		m_pControlPoint[0] = m_pControlPoint[m_nNumControlPoint-4];
		m_pControlPoint[1] = m_pControlPoint[m_nNumControlPoint-3];
		m_pControlPoint[m_nNumControlPoint-2] = m_pControlPoint[2];
		m_pControlPoint[m_nNumControlPoint-1] = m_pControlPoint[3];
	}

	void SPEmitterBeam::Initialize()
	{
		SPEmitter::Initialize();
	}

	void SPEmitterBeam::Render()
	{
		SPRenderBeam( this );
	}

	void SPEmitterBeam::Advance( float fElapsedTime )
	{
		SPEmitter::Advance( fElapsedTime );

		Reshape();
		SPAdvanceBeam( this, fElapsedTime );
	}

	void SPEmitterBeam::ClearModule()
	{
		SPEmitter::ClearModule();

		m_pModuleSource = NULL;
		m_pModuleTarget = NULL;
		m_pModuleShape = NULL;
	}

	void SPEmitterBeam::CreateFileBuffer( SPFileBuffer* pFB )
	{
		HRESULT hr;
		ID3DBlob* pBlob = NULL;

		SPFileBuffer* pEmitterFB = new SPFileBuffer();
		SPEmitter::CreateFileBuffer( pEmitterFB );

		int numbyte = pEmitterFB->nNumByte;
		numbyte += sizeof( EmitterBeamFileHead );

		EmitterBeamFileHead head;
		ZeroMemory( &head, sizeof(EmitterBeamFileHead) );

		head.fWidthScale = m_fWidthScale;
		head.fNoiseSpeed = m_fNoiseSpeed;
		head.fNoiseScale = m_fNoiseScale;
		head.nTessellationAmount = m_nTessellationAmount;
		head.nNumControlPoint = m_nNumControlPoint - 4;
		head.bUpdatePerFrame = m_bUpdatePerFrame;
		head.bFaceToCamera = m_bFaceToCamera;
		head.bEnableNoise = m_bEnableNoise;
		if ( m_pModuleShape )
		{
			head.bModuleShape = true;
			head.ModuleShape.InitByModule( m_pModuleShape );
		}

		if ( m_pModuleSource )
		{
			head.bModuleSource = true;
			head.ModuleSource.InitByModule( m_pModuleSource );
		}

		if ( m_pModuleTarget )
		{
			head.bModuleTarget = true;
			head.ModuleTarget.InitByModule( m_pModuleTarget );
		}

		head.bTexture = false;
		if ( m_pTex )
		{
			V( D3DX11SaveTextureToMemory( SPGetD3D11DeviceContext(), m_pTex, D3DX11_IFF_DDS, &pBlob, NULL ) );
			numbyte += pBlob->GetBufferSize();			
			head.bTexture = true;		
			head.nTextureBufferSize = pBlob->GetBufferSize();
		}

		pFB->CreateBuffer( numbyte );
		BYTE* pBuf =  pFB->pFileBuffer;
		// Emitter
		CopyMemory( pBuf, pEmitterFB->pFileBuffer, pEmitterFB->nNumByte );
		pBuf += pEmitterFB->nNumByte;

		CopyMemory( pBuf, &head, sizeof( EmitterBeamFileHead ) );
		pBuf += sizeof( EmitterBeamFileHead );

		if ( head.bTexture )
		{
			CopyMemory( pBuf, pBlob->GetBufferPointer(), pBlob->GetBufferSize() );
			pBuf += pBlob->GetBufferSize();
		}

		SAFE_DELETE( pEmitterFB );
		SAFE_RELEASE( pBlob );
	}

	void SPEmitterBeam::CreateFromFileBuffer( BYTE* pBufPtr )
	{
		HRESULT hr;

		SPEmitter::CreateFromFileBuffer( pBufPtr );

		UINT offset = ( (EmitterFileHead*)pBufPtr )->nByteCount;
		BYTE* pBuf = pBufPtr + offset;
		EmitterBeamFileHead* pHead = (EmitterBeamFileHead*)pBuf;

		m_fWidthScale = pHead->fWidthScale;
		m_fNoiseSpeed = pHead->fNoiseSpeed;
		m_fNoiseScale	= pHead->fNoiseScale;
		m_nTessellationAmount = pHead->nTessellationAmount;
		m_bUpdatePerFrame = pHead->bUpdatePerFrame;
		m_bFaceToCamera = pHead->bFaceToCamera;
		m_bEnableNoise = pHead->bEnableNoise;
		Create( pHead->nNumControlPoint );

		if ( pHead->bModuleShape )
		{
			m_pModuleShape = pHead->ModuleShape.ToModule();
		}

		if ( pHead->bModuleSource )
		{
			m_pModuleSource = ( SPModuleBeamSource* )pHead->ModuleSource.ToModule();
		}

		if ( pHead->bModuleTarget )
		{
			m_pModuleTarget = ( SPModuleBeamTarget* )pHead->ModuleTarget.ToModule();
		}

		if ( pHead->bTexture )
		{
			pBuf += sizeof( EmitterBeamFileHead );
			V( D3DX11CreateTextureFromMemory( SPGetD3D11Device(), pBuf, pHead->nTextureBufferSize, NULL, NULL, &m_pTex, NULL) );
			V( D3DX11CreateShaderResourceViewFromMemory( SPGetD3D11Device(), pBuf, pHead->nTextureBufferSize, NULL, NULL, &m_pTexSRV, NULL) );
		}
	}

	bool SPEmitterBeam::SetSPModule( SPModule* pModule )
	{
		if ( SPModuleBeamSource* p = dynamic_cast<SPModuleBeamSource*>( pModule ) )
		{			
			m_pModuleSource = p;			
			return true;
		}

		if ( SPModuleBeamTarget* p = dynamic_cast<SPModuleBeamTarget*>( pModule ) )
		{
			m_pModuleTarget = p;
			return true;
		}

		if ( SPModuleBeamShape* p =dynamic_cast<SPModuleBeamShape*>( pModule ) )
		{
			m_pModuleShape = p;
			return true;
		}

		return SPEmitter::SetSPModule( pModule );
	}

	HRESULT SPEmitterBeam::CreateTextureFromFile( const wchar_t* file )
	{
		HRESULT hr = S_OK;

		V_RETURN( D3DX11CreateTextureFromFile(  m_pDevice, file, NULL, NULL, &m_pTex, NULL ) );
		V_RETURN( D3DX11CreateShaderResourceViewFromFile(  m_pDevice, file, NULL, NULL, &m_pTexSRV, NULL ) );

		return hr;
	}
}